﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using Bitacora;

namespace BusinessLayer
{
    public enum NIVEL_SEGURIDAD_IMPERSONALIZACION : int
    {
        Anonima = 0,
        Identificacion = 1,
        Impersonalizacion = 2,
        Delegada = 3
    }
    class IIF_Impersonalizacion
    {
        private System.Security.Principal.WindowsImpersonationContext nuevoUsuario;
        private string nombreUsuarioWindowsActual;
        private string nombreDominioWindows;

        // Obtiene Token Usuario
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        // Cierra manejadores abiertos devueltos por el metodo LogonUser
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        // Crea manejador token duplicado
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
            int SEGURIDAD_IMPERSONALIZACION, ref IntPtr DuplicateTokenHandle);

        public IIF_Impersonalizacion()
        {
            nombreUsuarioWindowsActual = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

            string usuarioTemporal = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
            if (usuarioTemporal.IndexOf("\\") != -1)
            {
                string[] nombreUsuario = new String[2];
                char[] divisor = { '\\' };
                nombreUsuario = usuarioTemporal.Split(divisor);
                nombreDominioWindows = nombreUsuario[0];
            }
        }


        /// <summary>
        /// Realiza la impersonalización de un usuario. Si es satisfactoria, retorna 
        /// un WindowsImpersonationContext de la identidad del nuevo usuario.
        /// </summary>
        /// <param name="sUsername">Nombre de usuario a impersonalizar</param>
        /// <param name="sDomain">Nombre de dominio Windows</param>
        /// <param name="sPassword">Password de usuario al impersonalizar</param></param>
        /// <returns></returns>
        private WindowsImpersonationContext ImpersonalizarUsuario(string nomUsuario, string passwordUsuario, string nomDominio)
        {
            // Inicializar tokens
            IntPtr manejadorTokenExistente = new IntPtr(0);
            IntPtr manejadorTokenDuplicado = new IntPtr(0);
            manejadorTokenExistente = IntPtr.Zero;
            manejadorTokenDuplicado = IntPtr.Zero;

            // Si el dominio no fue ingresado, se usa el nombre de la máquina local
            if (String.IsNullOrEmpty(nomDominio))
                nomDominio = System.Environment.MachineName;

            try
            {
                string textoResultado = null;

                const int LOGON32_PROVIDER_DEFAULT = 0;

                // Crear token
                const int LOGON32_LOGON_INTERACTIVE = 2;

                // Obtener manejador para el Token
                bool resultadoImpersonalizacion = LogonUser(nomUsuario, nomDominio, passwordUsuario,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref manejadorTokenExistente);

                // fallo la impersonalización?
                if (!resultadoImpersonalizacion)
                {
                    int numeroCodigoError = Marshal.GetLastWin32Error();
                    textoResultado = "IniciarSesionUsuario() falló con código de error: " + numeroCodigoError + "\r\n";
                }

                // Identidad antes de impersonalizar
                textoResultado += "Antes Impersonalización: " + WindowsIdentity.GetCurrent().Name + "\r\n";

                bool resultadoDuplicacionToken = DuplicateToken(manejadorTokenExistente, (int)NIVEL_SEGURIDAD_IMPERSONALIZACION.Impersonalizacion, ref manejadorTokenDuplicado);

                // falló DuplicarToken?
                if (!resultadoDuplicacionToken)
                {
                    int numCodigoError = Marshal.GetLastWin32Error();
                    CloseHandle(manejadorTokenExistente); // close existing handle
                    textoResultado += "DuplicarToken() falló con código de error: " + numCodigoError + "\r\n";
                    Services.EnviarLog("Unisys Batch Importer To IIF", 0, textoResultado, "ImpersonalizarUsuario", Bitacora.TipoError.Informacion);
                    return null;
                }
                else
                {
                    // Crear nueva identidad usando token primario
                    WindowsIdentity nuevaIdentificacion = new WindowsIdentity(manejadorTokenDuplicado);
                    WindowsImpersonationContext usuarioImpersonalizado = nuevaIdentificacion.Impersonate();

                    // Revisar identidad después de impersonalizar
                    textoResultado += "Después Impersonalización: " + WindowsIdentity.GetCurrent().Name + "\r\n";
                    Services.EnviarLog("Unisys Batch Importer To IIF", 0, textoResultado, "ImpersonalizarUsuario", Bitacora.TipoError.Informacion);
                    return usuarioImpersonalizado;
                }
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                // Cerrar Manejador(es)
                if (manejadorTokenExistente != IntPtr.Zero)
                    CloseHandle(manejadorTokenExistente);
                if (manejadorTokenDuplicado != IntPtr.Zero)
                    CloseHandle(manejadorTokenDuplicado);
            }
        }

        public bool RevertirImpersonalizacion()
        {
            try
            {
                string resultadoReversion = "Usuario Actual Antes de Revertir Imperzonalización: " + nombreUsuarioWindowsActual + "\r\n";
                
                // Revertir a usuario previo
                nuevoUsuario.Undo();
                // Actualizar la ejecucion
                nombreUsuarioWindowsActual = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
                resultadoReversion += "Usuario Actual Después de Revertir Imperzonalización: " + nombreUsuarioWindowsActual + "\r\n";
                Services.EnviarLog("Unisys Batch Importer To IIF", 0, resultadoReversion, "ImpersonalizarUsuario", Bitacora.TipoError.Informacion);
                return true;
            }
            catch { return false; }
        }

        public bool RealizarImpersonalizacion(string nombreUsuario, string passUsuario, string nombreDominio)
        {
                try
                {
                    // Realizar impersonalizacion de usuario
                    nuevoUsuario = this.ImpersonalizarUsuario(nombreUsuario, passUsuario, nombreDominio);
                    nombreUsuarioWindowsActual = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
                    return true;
                }
                catch (Exception ex)
                {
                    return false;
                }
        }


    }
}